<template>
<!-- treeData.children || 
      (ipcType === 'special' && recordMgtNodeModeTableData) -->
    <div class="IpcTree" 
      v-if="!catalogLoading" 
      :class="[$route.path.split('/').slice(-1), $i18n.locale]" 
      ref="IpcTree" 
      style="pointer-events:auto"
    >
    <recurse-virtual-tree
      ref="childTree"
      :option="virtualOption"
      :situation="situation"
      :filterType="filterType"
      :treeData="treeData"
      :filterMode="filterMode"
      :tableData="recordMgtNodeModeTableData"
      :clickRow="clickRow"
      :ipcType="ipcType"
      :ipcList="ipcList"
      :isFilter="isFilter"
      :specialList="specialList"
      @closeSeaerch="isFilter = false"
      @updateIpcList="updateIpcList"
      @updateCurrentDragObj="updateCurrentDragObj"
      @addCatalog="addCatalogItem"
      @deleteCatalog="deleteCatalogItem"
      @modifyCatalog="modifyCatalogItem"
      @showDataBase="showDataBase"
      @changeSelectIp="changeSelectIp"
      @selectIpc="selectIpc"
      @moveCatalog="moveCatalog"
    />
    <!-- <div
      style="height: 100%;"
      v-if="loading"
    >
      <el-skeleton :rows="18" />
    </div> -->
    <!-- 新增弹框 -->
    <el-dialog
      :title="$t('common.addCatalog')"
      :visible.sync="dialogVisible"
      :append-to-body="true"
      width="680px"
      class="pic-dialog"
      :before-close="handleClose"
    >
      <el-form
        :model="addData"
        :rules="addRules"
        ref="addData"
      >
        <el-form-item
          prop="name"
          :label="$t('common.newCatalogName')"
          :label-width="setWidthFn({ zh: '110', en: '150' }) + 'px'"
        >
          <el-input
            style="width: 100%"
            clearable
            v-model.trim="addData.name"
            :placeholder="$t('common.inputTips')"
          ></el-input>
        </el-form-item>
      </el-form>
      <span slot="footer" class="dialog-footer">
        <el-button @click="handleClose">{{
          $t("common.cancelTab")
        }}</el-button>
        <el-button type="primary" @click="handleAddClick('addData')">{{
          $t("common.okTab")
        }}</el-button>
      </span>
    </el-dialog>

    <!-- 编辑弹框 -->
    <el-dialog
      :title="$t('common.editCatalog')"
      :visible.sync="dialogEditVisible"
      :append-to-body="true"
      width="680px"
      class="pic-dialog"
      :before-close="handleClose"
    >
      <el-form
        :model="modifyData"
        :rules="modifyRules"
        ref="modifyData"
      >
        <el-form-item
          prop="new_name"
          :label="$t('common.newCatalogName')"
          :label-width="setWidthFn({ zh: '110', en: '150' }) + 'px'"
        >
          <el-input
            style="width: 100%"
            clearable
            v-model.trim="modifyData.new_name"
            :placeholder="$t('common.inputTips')"
          ></el-input>
        </el-form-item>
      </el-form>
      <span slot="footer" class="dialog-footer">
        <el-button @click="handleClose">{{
          $t("common.cancelTab")
        }}</el-button>
        <el-button type="primary" @click="handleModifyClick('modifyData')">{{
          $t("common.okTab")
        }}</el-button>
      </span>
    </el-dialog>
  </div>
  <div
   style="height: 100%;"
   class="treeLoading"
   :class="[$route.path.split('/').slice(-1), $i18n.locale]"
   v-else
  >
    <el-table 
     v-loading="catalogLoading"
     empty-text=" "
    >
    </el-table>
  </div>
</template>

<script>
import RecurseVirtualTree from "./RecurseVirtualTree.vue";
import { 
  getCfgCataLog,
  addCfgCataLog,
  modCfgCataLog,
  deleteCfgCataLog
} from "@/api/catalog";
import { 
  getIpcs,
  getDbIpcs,
  getIpcPic,
} from "@/api/ipc";
import { setWidth } from "@/utils";
import {
  insertSorted,
  sortIpcList
} from '@/utils/common';
let ipcMap, disposedIpcMap, complementIpcMap, complementMap;
import { cloneDeep } from 'lodash';
export default {
  name: 'IpcTree',
  components: {
    RecurseVirtualTree,
  },
  provide() {
    return {
      getCurDragObj: () => this.curDragObj
    }
  },
  computed: {
    // 是目录管理或ipc管理吗?
    isCatalogOrIpcMgt() {
      return this.$route.path === '/config/catalog' || this.$route.path === '/config/ipcManagement'
    },
  },
  watch: {
    filterMode (val) {
      this.catalogLoading = true;
    },
    ipcType (val) {
      this.catalogLoading = true;
    },
    recordMgtNodeModeTableData (newVal, oldVal) {
      console.log(this.catalogLoading, 'catalogLoading');
      console.log(newVal, 'newVal173');
      debugger
    }
  },
  props: {
    isSpecialOver: {
      type: Boolean,
    },
    filterMode: {
      type: String,
    },
    situation: {
      type: String,
    },
    filterType: {
      type: String,
    },
    ipcType: {
      type: String,
    },
    recordMgtNodeModeTableData: {
      type: Array,
      default: () => []
    },
    clickRow: {
      type: Object,
      default: () => {}
    },
    virtualOption: {
      type: Object,
      default: () => {}
    }
  },
  data() {
    const validateCatalogName = (rule, value, callback) => {
      // const regex = /^(?!.*\/)(?!.*根目录).+$/;
      // 这个正则表达式表示 不匹配 '/' 不匹配根目录和默认陌路一级它们的英文
      // ?!表示预测先行断言，后面的内容不能匹配，.表示除了换行符外的字符  *表示0或者多个 +表示1或者以上
      const regex = /^(?!.*\/)(?!.*(根目录|root|raíz|默认目录|Default directory|Directorio por defecto)).+$/
      if (value.trim().length < 1) {
        callback(new Error(this.$t("common.emptyTips")));
      } else if (!regex.test(value)) {
        // 一旦包含了 / 或者根目录 或者默认目录 regex.test(value)就是false  就啊哟报错
        callback(new Error(this.$t("ipcList.not allowed enter root")));
      } else if (value.length > 64) {
        callback(new Error(this.$t("ipcList.not allowed over 64 bits")));
      } else {
        callback();
      }
    };
    return {
      orgList: [],
      ipcList: [],
      treeData: {},
      rootNode: [
        {
          name: this.$t('ipcList.root'),
          id: 0,
          children: [
            {
              name: this.$t('ipcList.default catalog compare'),
              id: 1,
              children: [],
              ipc_list: [],
              showChildren: false,
              loading: false,
              path: this.$t('ipcList.default catalog'),
              type: 'catalog',
            },
          ],
          type: 'catalog',
          path: this.$t('ipcList.rootCompare'),
          ipc_list: [],
          showChildren: true,
          loading: false
        },
      ],
      id: 2,
      filterValueInput: '',
      dialogVisible: false, // 新增弹框
      dialogEditVisible: false, // 编辑弹框
      type: 'add', // 新增还是编辑
      addData: {
        old_name: "",
        name: ""
      },
      addRules: {
        name: [
          { required: true, trigger: ["blur", "change"], validator: validateCatalogName }
        ]
      },
      modifyRules: {
        new_name: [
          { required: true, trigger: ["blur", "change"], validator: validateCatalogName }
        ]
      },
      modifyData: {
        old_name: "",
        new_name: ""
      },
      addOrEditData: {}, // 新增的目录数据
      editOrEditData: {}, // 新增的目录数据
      curDragObj: null, // 被拖拽对象
      catalogLoading: true, // 加载
      flattenTree: [], // 拍平的树
      isFilter: false, // 搜索数据
      specialList: [], // 特殊ipc的数据
      specialAllList: [], // 所有的特殊ipc数据
    };
  },
  created() {
    // 初始化ipc
    debugger
    if (!this.$store.state.treeJumpData) { 
      this.filterIpc("");
    } else {
      // 如果涉及跳转
      if (
        this.$store.state.treeJumpData.otherData && 
        (
          this.$store.state.treeJumpData.otherData.ipcType === 'special' || 
          this.$store.state.treeJumpData.otherData.filterMode === 'nodeMode'
        )
      ) {
        this.getDbIpcs(this.$store.state.treeJumpData.otherData.selectUuid)
      }
      else {
        // 如果跳转里面记录了数据，就要用旧的树
        this.treeData = this.$store.state.treeJumpData.treeData
        this.catalogLoading = false;
        debugger
      }
    }
  },
  mounted() {
    // 备用，且让父组件的tree数据有level和showChildren等内容,删除目录时有用
    setTimeout(() => {
      this.flattenTree = this.flatten(this.treeData.children, 'children', 1, {
        level: 0,
        showChildren: true,
        expand: true,
        children: this.treeData.children
      }, undefined, undefined)
    }, 500);
  },
  beforeDestroy() {
    this.catalogLoading = false;
    debugger
    for (const item of this.ipcList) {
      item.state.channelState = null
      item.state = {}
      item.state = null
    }
    this.ipcList.length = 0
    this.orgList.length = 0
    if (ipcMap) ipcMap.clear();
    if (disposedIpcMap) disposedIpcMap.clear();
    if (complementIpcMap) complementIpcMap.clear();
    if (complementMap) complementMap.clear();
    ipcMap = null;
    disposedIpcMap = null;
    complementIpcMap = null;
    complementMap = null;
    this.treeData = null
    if (!this.$store.state.treeJumpData) {
      this.rootNode.length = 0
      this.rootNode = null
    }
  },
  methods: {
    flatten (
      list = [],
      childKey = 'children',
      level = 1,
      parent = null,
      defaultExpand = true,
      isSearch
        ) {
        let arr = []
          // 无ipc
        list.forEach((item) => {
          this.$set(item, 'level', level)
          if (item.showChildren === undefined) {
            item.showChildren === defaultExpand
            this.$set(item, 'showChildren', defaultExpand)
          }
          if (item.visible === undefined && level > 2) {
            this.$set(item, 'visible', false)
          } else if (item.visible === undefined) {
            this.$set(item, 'visible', true)
          }
          // if (!parent.visible || !parent.expand) {
          //   item.visible = false
          // }
          this.$set(item, 'parent', parent)
          // 当前目录
          arr.push(item)
          if (this.situation !== 'catalog' && this.situation !== 'ipcMgt') {
            // 当前目录下的ipc
            if (item.ipc_list && item.ipc_list.length > 0) {
              if (isSearch) {
                // 搜索，目录下ipc要展开
                item.ipc_list.forEach(ipc => {
                  this.$set(ipc, 'visible', true)
                  this.$set(ipc, 'level', level + 1)
                  arr.push(ipc)
                })
              } else {          
                // 不是搜索，不展开    
                item.ipc_list.forEach(ipc => {
                  // 根据父亲的展示与否设置ipc的显示
                  this.$set(ipc, 'visible', item.showChildren)
                  this.$set(ipc, 'level', level + 1)
                  arr.push(ipc)
                })
              }
            }
          }
          // 当前目录下的子目录
          if (item[childKey] && item[childKey].length > 0) {
            arr.push(...this.flatten(
              item[childKey],
              childKey,
              level + 1,
              item,
              defaultExpand,
              isSearch
            ))
          }
        })
        return arr
    },
    clearTreeData () {
      this.treeData = {}
      // this.$store.commit("setTreeDataMark", this.treeData); // 记录树数据
    },
    async refreshLiveIpc () {
      try {
        await this.queryOrganizationList();
        await this.queryIpcList();
        if (this.$route.fullPath === "/live") {
          await this.updateIpcPictureList(this.ipcList)
        }
        this.$refs.childTree.refreshCatalogIpc(this.orgList, this.ipcList)
      } catch (error) {
        console.log(error,'error');
      }
    },
    showDataBase (data) {
      this.$emit('showDataBase', data) // 热力图展示
    },
    changeSelectIp (ip, uuid) {
      this.$emit('changeSelectIp', ip, uuid) // 选中的ip，给到热力图和数据图
    },
    selectIpc (type, data, ipcList) {
      this.$emit('selectIpc', type, data, ipcList) // 选中的ip，给到热力图和数据图
    },
    valueFilterHandler () {

    },
    getCatalogFold() {
      this.getIpcTreeData().then(() => {
        this.$message.success(this.$t("common.refresh_success"));
      }).catch(() => {
        this.$message.error(this.$t("common.refresh_error"));
      });
    },
    searchCatalog () {

    },
    async filterIpc(value) {
      try {
        // this.treeData = {};
        this.catalogLoading = true;
        // 初始化
        if (value === "") {
          this.rootNode = [
            {
              name: this.$t('ipcList.root'),
              id: 0,
              children: [
                {
                  name: this.$t('ipcList.default catalog compare'),
                  id: 1,
                  children: [],
                  ipc_list: [],
                  showChildren: false, // 初始化默认目录是不展开
                  loading: false,
                  path: this.$t('ipcList.default catalog'),
                  type: 'catalog',
                },
              ],
              type: 'catalog',
              path: this.$t('ipcList.rootCompare'),
              ipc_list: [],
              showChildren: true,
              loading: false
            },
          ]
          await this.getIpcTreeData();
          if (!(this.situation === 'recordMgt' && this.ipcType === 'special')) {
            this.catalogLoading = false;
          }
        } 
        
        else {
          this.rootNode = [
            {
              name: this.$t('ipcList.root'),
              id: 0,
              children: [
                {
                  name: this.$t('ipcList.default catalog compare'),
                  id: 1,
                  children: [],
                  ipc_list: [],
                  showChildren: true, // 改为true
                  loading: false,
                  path: this.$t('ipcList.default catalog'),
                  type: 'catalog',
                },
              ],
              type: 'catalog',
              path: this.$t('ipcList.rootCompare'),
              ipc_list: [],
              showChildren: true,
              loading: false
            },
          ]
          if (this.isCatalogOrIpcMgt && this.filterType === 'catalog') {
            // 目录管理和ipc管理搜目录
            let filterCatalogList = this.orgList.filter((catalog) =>
              this.filterCatalogByName(catalog, value)
            );
            this.setCatalogTreeData(filterCatalogList, value);
            this.$set(this.treeData, "children", this.rootNode);
            // this.$store.commit("setTreeDataMark", this.treeData); // 记录树数据

          } 

          else if (!this.isCatalogOrIpcMgt && this.filterType === 'catalog') {
            // 其它页面搜目录
            let filterCatalogList = this.orgList.filter((catalog) =>
              this.filterCatalogByName(catalog, value)
            );
            this.setTreeData(this.ipcList, filterCatalogList, value);
            this.$set(this.treeData, "children", this.rootNode);
            // this.$store.commit("setTreeDataMark", this.treeData); // 记录树数据

          }

          else {
            // ipc过滤后
            const filterIpcList = this.ipcList.filter((ipc) =>
              this.filterIpcByNameOrIp(ipc, value)
            );
            this.setTreeData(filterIpcList);
            // 特殊情况1：默认目录有数据，默认目录应该展开
            if (
              this.rootNode[0] && 
              this.rootNode[0].children[0] && 
              this.rootNode[0].children[0].path === this.$t('ipcList.default catalog')
            ) {
              this.$set(this.rootNode[0].children[0], 'showChildren', true)
            }
            this.$set(this.treeData, "children", this.rootNode);
            // this.$store.commit("setTreeDataMark", this.treeData); // 记录树数据

          }

          this.$refs.childTree.updateFlatten(this.treeData)
          this.$refs.childTree.updateView(true)
          this.flattenTree = this.$refs.childTree.flatten(this.treeData.children, 'children', 1, {
            level: 0,
            showChildren: true,
            expand: true,
            children: this.treeData.children
          }, undefined, value)
          this.catalogLoading = false;
          debugger
        }
      } catch (error) {
        this.catalogLoading = false;
        debugger
        console.log(error, 'error');
      }
    },
    async getDbIpcs(searchValue) {
      try {
        this.catalogLoading = true
        // this.treeData = {} // 清空里面的数据
        // 如果特殊ipc列表有值，并且是搜索，
        if ((searchValue || searchValue === '') && this.specialAllList.length > 0) {
          this.specialList = this.specialAllList.filter(item => item.uuid.includes(searchValue))
          this.catalogLoading = false
          debugger
        }
        else {
          if (this.ipcList.length === 0) {
            await this.queryIpcList();
            if (this.$route.fullPath === "/live") {
              await this.updateIpcPictureList(this.ipcList)
            }
          }
          if (
            this.$store.state.treeJumpData &&
            this.$store.state.treeJumpData.otherData.filterMode === 'nodeMode' && 
            this.$route.query && 
            this.$route.query.filterType === 'uuid'
          ) { // 这个uuid代表filter过滤时的uuid，跳转过去显示IPCUUID，如果是特殊IPC这个值是special
            // 录像管理-节点模式-常规ipc的指定数据
            this.specialAllList = this.ipcList
            if (searchValue) {
              this.specialList = this.specialAllList.filter(item => item.uuid.includes(searchValue))
            }
            this.catalogLoading = false
            debugger
          } else {
            // 否则都要初始化特殊ipc
            getDbIpcs()
            .then((response) => {
              let dbIpcList = response.data.result;
              let sameIpc = [];
              let uuidList = [];

              for (let i = 0; i < this.ipcList.length; i++) {
                uuidList.push(this.ipcList[i].uuid);
              }
              for (let j = 0; j < dbIpcList.length; j++) {
                for (let i = 0; i < uuidList.length; i++) {
                  if (uuidList[i] == dbIpcList[j].uuid) {
                    sameIpc.push(dbIpcList[j]);
                  }
                }
              }
              dbIpcList = dbIpcList.filter(
                (v) => !sameIpc.some((item) => item === v)
              );
              if (dbIpcList) {
                dbIpcList.map((item) => {
                  item.recordList = [];
                  item.expand = true;
                });
                this.specialAllList = dbIpcList;
              } else {
                this.specialAllList = [];
              }
              // 在这里去搜索指定uuid
              if (searchValue) {
                this.specialList = this.specialAllList.filter(item => item.uuid.includes(searchValue))
              }
              // 就是初始化没有搜索
              else {
                this.specialList = this.specialAllList
              }
              this.catalogLoading = false
              debugger
            })
            .catch((error) => {
              console.log(error,'error');
              this.listLoading = false;
              this.catalogLoading = false
              debugger
            });
          }
        }
      } catch (error) {
        console.log(error, 'error')
      }
    },
    async getIpcTreeData() {
      this.$set(this.treeData, "children", []);
      try {
        await this.queryOrganizationList();
        // 在ipc管理和目录管理页面不需要重复拿IPCS
        if (!(this.situation === 'ipcMgt' || this.situation === 'catalog')) {
          await this.queryIpcList();
        }
        if (this.$route.fullPath === "/live") {
          await this.updateIpcPictureList(this.ipcList)
        }
        if (this.situation === 'catalog' || this.situation === 'ipcMgt') {
          this.setCatalogTreeData();
        } else {
          this.setTreeData(); 
        }
        this.$set(this.treeData, "children", this.rootNode);
        // this.$store.commit("setTreeDataMark", this.treeData); // 记录树数据
      } catch (error) {
        console.log(error, 'error');
      }
    },
    // 建树，对应的ipc列表和目录列表
    setTreeData(filterList, catalogList, searchValue) {
      // 搜索
      if (filterList) {
        // 搜索不到数据
        if (!filterList || filterList.length === 0) {
          this.rootNode = []
          return
        }

        // 创建IPC映射，UUID映射成下标
        ipcMap = filterList.reduce((map, ipc, index) => {
          map.set(ipc.uuid, index);
          return map;
        }, new Map());

        // 目录及目录下的IPC-UUID
         disposedIpcMap = new Map(); // 已经分配目录的ipc


        // 用搜出来的目录建树->搜目录
        if (catalogList) {
          catalogList.forEach((element) => {
            const path = element.name;
            if (element.ipc_list) {
              const keysArray = Object.keys(element.ipc_list); // ipc_list的keys
              let ipc_list = [];
              keysArray.forEach((key) => {
                // 如果目录中包含了ipc列表中的ipc，那么加入已使用map
                if (ipcMap.has(key)) {
                  let index = ipcMap.get(key);
                  disposedIpcMap.set(key, index);
                  ipc_list.push(filterList[index]);
                }
              });
              this.buildTree(path.slice(1), sortIpcList(ipc_list, 'name'), this.rootNode[0], true);
            } else {
              // 特殊情况，其它页面搜目录，没有ipc_list也要展示该目录
              this.buildTree(path.slice(1), [], this.rootNode[0], true);
            }

            // 搜IPC 如果目录下没有ipc_list属性，直接不展示
            // else {
            //   this.buildTree(path.slice(1), [], this.rootNode[0], true);
            // }
          });


          // 搜的是默认目录
          if (searchValue && searchValue === this.$t('ipcList.default catalog compare')) {
            complementIpcMap = new Map();
            complementIpcMap = this.complementOfMaps(ipcMap, disposedIpcMap);
            let complementIpcList = [];
            for (const key of complementIpcMap.keys()) {
              complementIpcList.push(filterList[complementIpcMap.get(key)]);
            }
            this.rootNode[0].children[0].ipc_list = sortIpcList(complementIpcList, 'name');
          }
          // 搜的是根目录
          else if (searchValue && searchValue === this.$t('ipcList.root')) {
            this.rootNode = [
              {
                name: this.$t('ipcList.root'),
                id: 0,
                children: [
                ],
                type: 'catalog',
                path: this.$t('ipcList.rootCompare'),
                ipc_list: [],
                showChildren: true,
                loading: false
              },
            ]
            return
          } else if (catalogList.length === 0) {
            // 搜其他目录没有任何数据
            this.rootNode = []
            return
          } else {
            this.rootNode[0].children = this.rootNode[0].children.filter(item => {
              return item.path !== this.$t('ipcList.default catalog')
            })
          }
        } else {
          // 用所有的目录建树->搜ipc
          this.orgList.forEach((element) => {
            const path = element.name;
            if (element.ipc_list) {
              const keysArray = Object.keys(element.ipc_list); // ipc_list的keys
              let ipc_list = [];
              keysArray.forEach((key) => {
                // 如果目录中包含了ipc列表中的ipc，那么加入已使用map
                if (ipcMap.has(key)) {
                  let index = ipcMap.get(key);
                  disposedIpcMap.set(key, index);
                  ipc_list.push(filterList[index]);
                }
              });
              this.buildTree(path.slice(1), sortIpcList(ipc_list, 'name'), this.rootNode[0], true);
            } 

            // 搜IPC 如果目录下没有ipc_list属性，直接不展示
            // else {
            //   this.buildTree(path.slice(1), [], this.rootNode[0], true);
            // }
          });

          // 取补集，即计算没有分配的ipc
          let complementIpcMap = new Map();
          complementIpcMap = this.complementOfMaps(ipcMap, disposedIpcMap);
          let complementIpcList = [];
          for (const key of complementIpcMap.keys()) {
            complementIpcList.push(filterList[complementIpcMap.get(key)]);
          }

          // 搜ipc默认目录有数据 或者 搜目录并且是默认目录
          if (complementIpcList.length > 0) {
            this.rootNode[0].children[0].ipc_list = sortIpcList(complementIpcList, 'name');
          }
          // 特殊情况：搜索ip时默认目录下没数据，不展示；因为默认目录是手动添加的
          else {
            this.rootNode[0].children = this.rootNode[0].children.filter(item => {
              return item.path !== this.$t('ipcList.default catalog')
            })
          }
        }
        
        // // 取补集，即计算没有分配的ipc
        // let complementIpcMap = new Map();
        // complementIpcMap = this.complementOfMaps(ipcMap, disposedIpcMap);
        // let complementIpcList = [];
        // for (const key of complementIpcMap.keys()) {
        //   complementIpcList.push(filterList[complementIpcMap.get(key)]);
        // }

        // // 搜ipc默认目录有数据 或者 搜目录并且是默认目录
        // if (complementIpcList.length > 0) {
        //   this.rootNode[0].children[0].ipc_list = sortIpcList(complementIpcList, 'name');
        // }
        // // 特殊情况：搜索ip时默认目录下没数据，不展示；因为默认目录是手动添加的
        // else {
        //   this.rootNode[0].children = this.rootNode[0].children.filter(item => {
        //     return item.path !== this.$t('ipcList.default catalog')
        //   })
        // }
        
        this.addPathToTree(this.rootNode[0]);
      }

      // 初始化
      else {
        // 创建IPC映射，UUID映射成下标
        ipcMap = this.ipcList.reduce((map, ipc, index) => {
          map.set(ipc.uuid, index);
          return map;
        }, new Map());

        // 目录及目录下的IPC-UUID
        disposedIpcMap = new Map(); // 已经分配目录的ipc
        this.orgList.forEach((element) => {
          const path = element.name;
          if (element.ipc_list && this.situation !== 'catalog' && this.situation !== 'ipcMgt') {
            const keysArray = Object.keys(element.ipc_list); // ipc_list的keys
            let ipc_list = [];
            keysArray.forEach((key) => {
              // 如果目录中包含了ipc列表中的ipc，那么加入已使用map
              if (ipcMap.has(key)) {
                let index = ipcMap.get(key);
                disposedIpcMap.set(key, index);
                ipc_list.push(this.ipcList[index]);
              }
            });
            ipc_list = sortIpcList(ipc_list, 'name');
            this.buildTree(path.slice(1), ipc_list, this.rootNode[0]);
          } else {
            this.buildTree(path.slice(1), [], this.rootNode[0]);
          }
        });

        // 取补集，即计算没有分配的ipc
        complementIpcMap = new Map();
        complementIpcMap = this.complementOfMaps(ipcMap, disposedIpcMap);
        let complementIpcList = [];
        for (const key of complementIpcMap.keys()) {
          complementIpcList.push(this.ipcList[complementIpcMap.get(key)]);
        }
        // 默认目录
        this.rootNode[0].children[0].ipc_list = sortIpcList(complementIpcList, 'name');
        this.addPathToTree(this.rootNode[0]);
      }
    },
    // 目录管理和ipc管理
    setCatalogTreeData(filterCatalogList, searchValue) {
      // 搜索
      if (filterCatalogList) {
        // 搜索不到数据；
        // 特殊情况，搜索的是根目录和默认目录这里也是0
        if (
          searchValue !== this.$t('ipcList.root') &&
          searchValue !== this.$t('ipcList.default catalog compare') &&
          filterCatalogList.length === 0
        ) {
          this.rootNode = []
          return
        }
        filterCatalogList.forEach((element) => {
          const path = element.name;
          // 传true表示搜索
          this.buildTree(path.slice(1), [], this.rootNode[0], true);
        });

        // 特殊情况：搜索根目录，只展示根目录
        if (searchValue === this.$t('ipcList.root')) {
          this.rootNode[0] = {
              name: this.$t('ipcList.root'),
              id: 0,
              children: [
              ],
              path: this.$t('ipcList.rootCompare'),
              ipc_list: [],
              showChildren: true,
              loading: false,
              type: 'catalog',
              visible: true,
            }
        }
        else if (searchValue === this.$t('ipcList.default catalog compare')) {
          // 特殊情况：搜索默认目录展示根目录和默认目录
          this.rootNode[0] = {
              name: this.$t('ipcList.root'),
              id: 0,
              children: [
                {
                  name: this.$t('ipcList.default catalog compare'),
                  id: 1,
                  children: [],
                  ipc_list: [],
                  showChildren: true,
                  loading: false,
                  path: this.$t('ipcList.default catalog'),
                  type: 'catalog',
                  visible: true,
                },
              ],
              path: this.$t('ipcList.rootCompare'),
              ipc_list: [],
              showChildren: true,
              loading: false,
              type: 'catalog',
              visible: true,
            }
        }
        else {
          // 目录管理和ipc管理，节点下都无ipc，直接为空数组
          this.rootNode[0].children[0].ipc_list = [];
          // 特殊情况：搜索其它目录不展示默认目录
          if (filterCatalogList) {
              this.rootNode[0].children = this.rootNode[0].children.filter(item => {
              return item.path !== this.$t('ipcList.default catalog')
            })
          }
        }
      }

      // 初始化
      else  {
        this.orgList.forEach((element) => {
          const path = element.name;
          this.buildTree(path.slice(1), [], this.rootNode[0]);
        });
      }
    
      
      this.addPathToTree(this.rootNode[0]);
    },
    buildTree(path, ipc_list, parentNode, isSearch = false) {
      // 特殊情况，搜索ip时，目录下没有这个ipc不构建这个目录；
      if (isSearch && ipc_list.length === 0 && this.filterType !== 'catalog') {
        return
      } 
      // 截取首个/的路径，若含有/说明还有子目录
      if (path.includes("/")) {
        let namelist = path.split("/");
        let childName = namelist[0];
        // 判断parentNode有没有重名，如果没有就新增
        let childNode = parentNode.children.find(
          (node) => node.name === childName
        );
        if (!childNode) {
          // 如果不存在相同名称的子节点，则创建新节点
          childNode = {
            name: childName,
            id: this.id,
            children: [],
            ipc_list: [],
            showChildren: isSearch,
            loading: false,
            type: 'catalog',
            visible: parentNode.showChildren, // 初始化/搜索，visible依赖父亲的showChildren与否 
          };
          this.id++;
          parentNode.children.push(childNode);
        }
        // 递归子目录
        let remainname = path.substring(namelist[0].length + 1);
        this.buildTree(remainname, ipc_list, childNode, isSearch);
      }
      // 没有子目录，ipc_list加在这个节点上
      // 如果有两个路径A/A1和A，其中A下面有ipc_list，先添加了A和A1节点了，再次添加A时，不需要新增节点，只需要新增ipc_lsit
      else {
        let childNode = parentNode.children.find((node) => node.name === path);
        if (!childNode) {
          // let ipcList = JSON.parse(JSON.stringify(ipc_list))
          let ipcList = ipc_list.filter(item => item.uuid).map(item => ({...item}));
          childNode = {
            name: path,
            id: this.id,
            children: [],
            ipc_list: ipcList,
            showChildren: isSearch,
            loading: false,
            type: 'catalog',
            visible: parentNode.showChildren, // 初始化/搜索，visible依赖父亲的showChildren与否 
          };
          this.id++;
          parentNode.children.push(childNode);
        } else {
          childNode.ipc_list = ipc_list;
        }
      }
    },
    // 获取组织列表
    queryOrganizationList() {
      let params = {
        parent_name: "/",
        recursive: true,
      };
      return new Promise((resolve,reject)=>{
        getCfgCataLog(params).then((response) => {
          this.orgList = this.sortCatalogList(response.data);
          resolve();
        }).catch(error=>{
          reject(error);
        });
      })
    },
    // 获取IPC列表
    async queryIpcList() {
      return new Promise((resolve,reject)=>{
        getIpcs().then(async (response) => {
          let arr = [];
          const data = response.data
          for (let item of data.ipcList) {
            let data = {
              uuid: item.uuid,
              ip: item.ip,
              name: item.name,
              state: item.state,
              vendor: item.vendor,
              type: item.type,
              recordExpiry: item.recordExpiry,
              appearance: item.appearance,
            }
            // data.state.channelState = null
            arr.push(data);
          }
          this.ipcList = arr;
          resolve();
        }).catch(error=>{
          reject(error);
        });
      })
    },
    updateIpcPictureList(arr) {
      const promises = arr.map(item => {
        if (item.state && (item.state.channelState[0].relayState === 'working' || item.state.channelState[1].relayState === 'working')) {
          return new Promise((resolve, reject) => {
            getIpcPic(item.uuid)
              .then(response => {
                const data = response.data;
                this.$set(item, 'picUrl', 'data:image/jpg;base64,' + data);
                resolve(item);
              })
              .catch(error => {
                reject(item);
              });
          }).then(res => console.log(res)).catch(err => console.log(err)); // new Promise外层增加.catch，捕获单个的promise的报错
        } else {
          return Promise.resolve(item);
        }
      });
      return Promise.all(promises);
    },
    // 递归计算IPC数量
    calculateIpcCount(org, ipcMap) {
      org.ipcCount = org.ipc_list.length;
      org.children.forEach((child) => {
        this.calculateIpcCount(child, ipcMap);
        org.ipcCount += child.ipcCount;
      });
    },
    // 查找ipc
    filterIpcByNameOrIp(ipc, value) {
      return (
        (this.filterType === "name" && ipc.name.includes(value)) ||
        (this.filterType === "uuid" && ipc.uuid.includes(value)) ||
        (this.filterType === "ip" && ipc.ip.includes(value)) ||
        (this.filterType === "nodeIp" && ipc.state.nodeIp.includes(value)) ||
        (this.filterType === "special" && ipc.state.nodeIp.includes(value))
      );
    },
    // 查找目录
    filterCatalogByName(catalog, value) {
      // 把/a/b/c的最后一个c拿出来
      let arr = catalog.name.split('/')
      return (
        (this.filterType === "catalog" && arr[arr.length - 1].includes(value))
      )
    },
    // 取A的补集
    complementOfMaps(mapA, mapB) {
       complementMap = new Map();
      // 遍历 Map A 的键
      for (const keyA of mapA.keys()) {
        // 检查键是否存在于 Map B 中
        if (!mapB.has(keyA)) {
          complementMap.set(keyA, mapA.get(keyA));
        }
      }
      return complementMap;
    },
    addPathToTree(treeData, parentPath = "") {
      if (!treeData.children || treeData.children.length < 1) {
        return;
      }
      for (const node of treeData.children) {
        const nodePath = parentPath + "/" + node.name;
        node.path = nodePath;
        // 如果当前节点有 ipc_list，为每个 ipc_list 添加路径
        if (node.ipc_list && node.ipc_list.length > 0) {
          for (const ipc of node.ipc_list) {
            ipc.path = nodePath + "/" + ipc.name; // 这里后面改
            // this.$set(ipc, 'path', nodePath + "/" + ipc.name)
          }
        }
        // 如果当前节点有子节点，递归调用
        if (node.children && node.children.length > 0) {
          this.addPathToTree(node, nodePath);
        }
      }
    },
    // 点击目录更新对应的Ipc列表
    updateIpcList(data) {
      let params = {
        catalogName: data.path,
      };
      if (this.situation === 'catalog') {
        this.$parent.$refs["container"].updataIpcList(params);
      } else if (this.situation === 'ipcMgt') {
        this.$parent.updataIpcList(params);
      }
    },
    // 关闭弹框
    handleClose() {
      if (this.type === 'add') {
        this.$refs['addData'] && this.$refs['addData'].resetFields();
        this.addData = {
          name: ''
        }
        this.dialogVisible = false;
      } else if (this.type === 'modify') {
        this.$refs['modifyData'].resetFields();
        this.modifyData = {
          old_name: "",
          new_name: ""
        }
        this.dialogEditVisible = false;
      }
    },
    // 多语言时宽度设置
    setWidthFn(obj) {
      return setWidth(obj);
    },
    // 新增目录
    addCatalogItem(item) {
      this.dialogVisible = true
      this.addOrEditData = item
      this.type = "add";
    },
    // 删除目录
    deleteCatalogItem(node) {
      this.$confirm(
        this.$t("ipcList.sure to remove the catalog"),
        this.$t("common.tips"),
        {
          confirmButtonText: this.$t("common.ok"),
          cancelButtonText: this.$t("common.cancel"),
          type: "warning"
        }
      )
        .then(() => {
          let data = {
            name: node.path
          };
          /* 用于传递给子组件进行更新 */
          let node2 = cloneDeep(node)
          deleteCfgCataLog(data)
            .then(response => {
                let arr = node.path.split('/')
                let parentName = arr.slice(0, arr.length - 1).join('/') ?arr.slice(0, arr.length - 1).join('/') : this.$t('ipcList.rootCompare')
                let { parent, element } = this.getChildAndParentTree(this.treeData.children, node.path)
                if (parent) {
                  let son = node.children
                  /* step1: 父组件的tree使用splice出现删除第一个元素;可能失效的情况，改用filter成功 */
                  // let ind =  fatherNode.children.findIndex(item => item.path === data.name)
                  // if (ind) fatherNode.children.splice(ind, 1)
                  parent.children = parent.children.filter(item => item.path !== data.name)
                  this.$message.success(response.data.message);

                  /* step2: 往parent.children里面push子子的内容，备注：删除某个节点的内容，子子节点不会一并被删除 */
                  if (son && son.length > 0) {
                    /* step2.1: 先改path，level，visible */
                    let newParentName = parent.path === this.$t('ipcList.rootCompare') ? '' : parent.path
                    let oldParentName = node.path === this.$t('ipcList.rootCompare') ? '' : node.path
                    for (let i = 0; i < son.length; i++) {
                      this.$refs.childTree.modifyParentPath(
                        son[i], 
                        newParentName, 
                        oldParentName,
                        parent.level + 1 // 目标目录的层级
                      )
                      /* step2.2 push过去 */
                      son[i].visible = true
                      insertSorted(parent.children, son[i])
                    }
                  }
                  // step3: 虚拟树重新拍平数组+更新视图
                }
                // 子组件的树数据更新
                this.$refs.childTree.deleteCatalogSure(node2)
                // step4: 更新所有组织树，否则添加或者编辑会出错
                this.queryOrganizationList()
                this.$nextTick(() => {
                  this.$refs.childTree.initFlatten()
                  this.$refs.childTree.updateView()
                })
            })
            .catch(error => {
              console.log(error, 'error');
              if (error.response && error.response.data && error.response.data.message) {
                this.$message({
                  showClose: true,
                  message: error.response.data.message,
                  type: 'error'
                });
              }
            });
        })
        .catch((err) => {
          console.log(err, 'err')
          this.$message({
            type: "info",
            message: this.$t("ipcMgt.deleteCancel")
          });
        });
    },
    // findFatherData(tree, path) {
    //   if (tree.path === path) {
    //     return tree
    //   } else {
    //     for (let i = 0; i < tree.children.length; i++) {
    //       // 遍历孩子
    //       const result = this.findFatherData(tree.children[i], path);
    //       if (result) {
    //         return result;
    //       }
    //     }
    //     return null
    //   }
    // },
    // 修改目录名称
    modifyCatalogItem(item) {
      this.dialogEditVisible = true
      this.editOrEditData = item
      this.type = "modify";
      this.modifyData.new_name = item.name // 回显用，用户修改
      this.modifyData.old_name = item.path
    },
    // 确认新增目录
    handleAddClick (formName) {
      this.$refs[formName].validate(valid => {
        if (valid) {
          let name = this.addOrEditData.path !== this.$t('ipcList.rootCompare') ?  this.addOrEditData.path + "/" + this.addData.name.trim() : "/" + this.addData.name.trim()
          // 存在同名目录 orgList里面的目录名是name属性
          let flag = this.orgList.find(item => item.name === name)
          if (flag) {
            this.$message({
              type: 'error',
              message: this.$t('ipcList.the catalog name has been used')
            })
            return
          }
          // 新增目录名
          let data = {
            name
          }
          return new Promise((resolve, reject) => {
            // step1：接口
            addCfgCataLog(data).then(response => {
              this.dialogVisible = false;
              // step2: 插入新的数据
              let node = {
                name: this.addData.name,
                id: this.id++,
                children: [],
                ipc_list: [],
                showChildren: false,
                path: data.name,
                level: this.addOrEditData.level + 1, // 父节点的层级+1
                visible: this.addOrEditData.showChildren, // 新增的元素的visible跟随父亲是否是showChildren
              }
              // step2.1: 有序插入指定位置,此时子组件的treeList已经更新
              insertSorted(this.addOrEditData.children, node)
              // step2.2: 更新子组件数据，更新视图虚拟树重新拍平数组+更新视图
              this.$refs.childTree.initFlatten()
              this.$refs.childTree.updateView()
              // step2.3: 更新组件的所有组织树
              this.queryOrganizationList()
              // step2.4 更新父组件对应节点信息
              let { element, parent } = this.getChildAndParentTree(
                this.treeData.children, 
                this.addOrEditData.path
              )
              // 注意！必须新建node2放到父element的children，如果用node，会导致引用，父和子用一个node，影响后续的操作
              let node2 = {
                name: this.addData.name,
                id: this.id++,
                children: [],
                ipc_list: [],
                showChildren: false,
                path: data.name,
                level: this.addOrEditData.level + 1, // 父节点的层级+1
                visible: this.addOrEditData.showChildren, // 新增的元素的visible跟随父亲是否是showChildren
              }
              if (element) {
                // step2.4 更新父组件的节点信息
                insertSorted(element.children, node2)
              }
              this.addOrEditData = null
              this.$message.success(response.data.message);
              this.$refs[formName].resetFields();
              resolve();
            }).catch(error => {
              console.log(error,'error');
              this.$message.error(error.response.data.message);
              reject(error);
            });
          })
        }
      })
    },
    // 确认编辑目录
    handleModifyClick(formName) {
      this.$refs[formName].validate(valid => {
        if (valid) {
          // 老目录的前缀 /a/b/c改名输入d，把/a/b拿过来和d拼
          let modify = this.modifyData.old_name
            .split("/")
            .slice(0, this.modifyData.old_name.split("/").length - 1)
            .join("/");
          let new_name = modify + "/" + this.modifyData.new_name;
          // 未做修改
          if (new_name === this.modifyData.old_name) {
            this.editOrEditData = null
            this.dialogEditVisible = false;
            this.$refs[formName].resetFields();
            return
          }
          // 存在同名目录
          let flag = this.orgList.find(item => item.name === new_name)
          if (flag) {
            this.$message({
              type: 'error',
              message: this.$t('ipcList.the catalog name has been used')
            })
            return
          }
          let data = {
            old_name: this.modifyData.old_name,
            new_name: new_name
          };
          return new Promise((resolve, reject) => {
            modCfgCataLog(data).then(response => {
              this.dialogEditVisible = false;
              // step1: 修改子组件内数据
              this.editOrEditData.name = this.modifyData.new_name
              this.editOrEditData.path = new_name
              // step1.1: 修改子组件 当前节点的 所有子节点的名字
              if (this.editOrEditData.children && this.editOrEditData.children.length > 0) {
                for (let i = 0; i < this.editOrEditData.children.length; i++) {
                  let node = this.editOrEditData.children[i]
                  this.modifyParentPath(node, data.new_name, data.old_name, node.level)
                }
              }
              // step2: 更新父组件的tree指定节点
              let { element, parent } = this.getChildAndParentTree(
                this.treeData.children, 
                this.modifyData.old_name // 旧目录
              )            
              // step2.1 修改指定节点的name和path
              if (element) {
                element.name = this.modifyData.new_name
                element.path = new_name
                // step2.2: 更新父组件的指定节点的所有子节点
                if (element.children && element.children.length > 0) {
                  for (let i = 0; i < element.children.length; i++) {
                    let node = element.children[i]
                    this.modifyParentPath(node, data.new_name, data.old_name, node.level)
                  }
                }
              }
              // step3 更新所有组织树
              this.queryOrganizationList()
              this.$message.success(response.data.message);
              this.$refs[formName].resetFields();
              resolve();
            }).catch(error => {
              if (error.response && error.response.data && error.response.data.message) {
                this.$message({
                  showClose: true,
                  message: error.response.data.message,
                  type: 'error'
                });
              }
              reject(error);
            });
          })
        }
      })
    },
    getChildAndParentTree(arr, targetName, parent = null) {
      for (let i = 0; i < arr.length; i++) {
        let currentObj = arr[i];
        if (currentObj.path === targetName) {
          return { element: currentObj, parent };
        }
        if (currentObj.children && currentObj.children.length > 0) {
          let result = this.getChildAndParentTree(
            currentObj.children,
            targetName,
            currentObj
          );
          if (result.element) {
            return result;
          }
        }
      }
      if (!parent) {
        return {
          element: null,
          parent: this.treeData.children[0],
        };
      } else {
        return { element: null, parent };
      }
    },
    // 对目录进行排序
    sortCatalogList(data) {
      data.sort((a, b) => a.name.localeCompare(b.name, "zh"));
      return data;
    },
    updateCurrentDragObj(item) {
      this.curDragObj = item;
    },
    // 子组件拖拽，父组件更新对应数据
    moveCatalog (oldParentName, newParentName, dragName, targetObj) {
      // targetObj子组件拖拽的数据，通过它找到父组件里面对应的元素element，修改element里面对应的children
      let { element, parent } = this.getChildAndParentTree(this.treeData.children, dragName)
      this.modifyParentPath(
        element, 
        newParentName, 
        oldParentName,
        targetObj.level + 1 // 目标目录的层级
      )
    },
        /*
      **修改移动的拖拽对象的所有后代的path
      *moveObj移动的对象
      *parentName修改的父目录的名称
      **
    */
    modifyParentPath(moveObj, newParent, oldParent, level) {
      // /a是目标目录 拖动/b/c 子目录：/b/c/d ；/b/c/d/e 
      // 把/b/c拖动到/a，直接把前面的/b都替换为/a，并且replace只会匹配一次，不用担心父子重名
      // 情况1：非根目录下的目录拖动到其它目录
      if (oldParent === '') {
        moveObj.path = newParent + moveObj.path
      } else {
        // 情况2：根目录下的目录移动到其它目录，/33 -> /22/331，此时就是/22/331/33
        moveObj.path = moveObj.path.replace(oldParent, newParent)
      }
      // 修改层级
      moveObj.level = level
      for (let i = 0; i < moveObj.children.length; i++) {
        this.modifyParentPath(moveObj.children[i], newParent, oldParent, level + 1)
      }
      return
    },
  },
};
</script>


<style lang="less" scoped>
.IpcTree {
  overflow: auto;
  position: relative;
  height: 100%;
  &.catalog {
    height: 89%;
  }
  &.ipcManagement {
    height: 90%;
  }
  &.recordManagement {
    width: 100%;
  }
  > .sb-tree {
    padding-left: 0;
  }
}


.treeLoading {
  height: 90%;
  .el-table {
    height: 80%;
  }
  &.catalog {
    height: 90%;
    .el-table {
      height: 85%;
    }
  }
}

.crud-div-right-input {
  width: 378px;
  height: 32px;
  ::v-deep .el-input__inner {
    line-height: 32px;
    height: 32px;
    font-size: 13px;
  }
}

.crud-div-right-btn.single-icon {
  //   color: #3c7eff;
  padding: 9px;
  margin: 0px 0px 0px 8px;
}
</style>